package com.zx.map.wx.context;

import com.alibaba.fastjson.JSONObject;
import com.zx.map.wx.bean.WxCurrentTokenBean;
import com.zx.map.wx.bean.WxMessageBean;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHost;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.log4j.Logger;

import javax.net.ssl.SSLContext;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.text.MessageFormat;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by IntelliJ IDEA.
 * User: Administrator
 * Date: 14-4-5
 * Time: 下午10:05
 * To change this template use File | Settings | File Templates.
 */
public class WxHelperContext {
    /**
     * log
     */
    private static Logger log = Logger.getLogger(WxHelperContext.class);
    /**
     * 获取token接口
     */
    private final static String getTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}";
    /**
     * 主动推送信息接口
     */
    private final static String sendMsgUrl = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token={0}";

    private static HttpClient webClient;
    private static WxHelperContext wxHelperContext;
    private static Map tokenMap = new ConcurrentHashMap();

    private WxHelperContext() {
        initWebClient();
    }

    public static WxHelperContext getWxHelperContext() {
        if (null == wxHelperContext) {
            wxHelperContext = new WxHelperContext();
        }
        return wxHelperContext;
    }

    private void initWebClient(String proxyHost, int proxyPort) {
        this.initWebClient();
        if (webClient != null && !StringUtils.isEmpty(proxyHost)) {
            HttpHost proxy = new HttpHost(proxyHost, proxyPort);
            webClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
        }
    }

    /**
     * @desc 初始化创建 WebClient
     */
    private void initWebClient() {
        log.info("initWebClient start....");
        try {
            PoolingClientConnectionManager tcm = new PoolingClientConnectionManager();
            tcm.setMaxTotal(500);
            SSLContext ctx = SSLContext.getInstance("TLS");
            X509TrustManager tm = new X509TrustManager() {
                public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                }

                public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                }

                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };
            ctx.init(null, new X509TrustManager[]{tm}, null);
            SSLSocketFactory ssf = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            Scheme sch = new Scheme("https", 443, ssf);
            tcm.getSchemeRegistry().register(sch);
            webClient = new DefaultHttpClient(tcm);
        } catch (Exception ex) {
            log.error("initWebClient exception", ex);
        } finally {
            log.info("initWebClient end....");
        }
    }

    /**
     * @param appid
     * @param secret
     * @return
     * @desc 获取授权token
     */
    public String getAccessToken(String appid, String secret) throws IOException {
        log.info("getAccessToken start.{appid=" + appid + ",secret:" + secret + "}");
        String url = MessageFormat.format(this.getTokenUrl, appid, secret);
        String response = executeHttpGet(url);
        log.info("getAccessToken return" + response);
        JSONObject jsonObject = JSONObject.parseObject(response);
        WxCurrentTokenBean wxCurrentTokenBean = new WxCurrentTokenBean();
        wxCurrentTokenBean.setToken(jsonObject.getString("access_token"));
        wxCurrentTokenBean.setLastQueryTime(System.currentTimeMillis());

        //保存key
        StringBuffer key = new StringBuffer(appid);
        key.append(secret);
        tokenMap.put(key.toString(), wxCurrentTokenBean);
        return wxCurrentTokenBean.getToken();
    }

    /**
     * @param token
     * @param msg
     * @return
     * @desc 推送信息
     */
    private String sendMessage(String token, String msg) throws IOException {
        log.info("sendMessage start.token:" + token + ",msg:" + msg);
        String url = MessageFormat.format(this.sendMsgUrl, token);
        HttpPost post = new HttpPost(url);
        ResponseHandler<?> responseHandler = new BasicResponseHandler();
        StringEntity entity = new StringEntity(
                msg, ContentType.create("application/json", "utf-8"));  //解决中文乱码
        post.setEntity(entity);
        String response = (String) this.webClient.execute(post, responseHandler);
        log.info("return response=====start======");
        log.info(response);
        log.info("return response=====end======");
        return response;
    }

    private String sendMessage(WxMessageBean wxMessageBean) throws IOException {
        String currentToken = getValidateToken(wxMessageBean.getAppId(), wxMessageBean.getAppSecu());
//        String template = "{\"touser\":\"" + wxMessageBean.getOpenId() + "\",\"msgtype\":\"text\"," +
//                "\"text\":{\"content\":\"" + wxMessageBean.getMessage() + "\"}}";
        String template = "{\"touser\":\""+ wxMessageBean.getOpenId()+"\", \"msgtype\":\"news\",\"news\":{\"articles\": [ {  \"title\":\""+wxMessageBean.getTitle()+"\", " +
                " \"description\":\""+wxMessageBean.getMessage()+"\", \"url\":\"\",  \"picurl\":\"\"    }  ]}}";
        sendMessage(currentToken, template);
        return null;
    }

    public void sendMessageCore(WxMessageBean wxMessageBean) throws IOException {
        try {
            sendMessage(wxMessageBean);
        } catch (ConnectTimeoutException cte) {
            log.error("连接超时", cte);
            sendMessage(wxMessageBean);//重发一次
        } catch (SocketTimeoutException ste) {
            log.error("Socket连接超时", ste);
            initWebClient();
            sendMessage(wxMessageBean);//重发一次
        } catch (Exception e) {
            log.error("内部异常", e);
        }
    }

    /**
     * 获取合法token
     * @param appid
     * @param secret
     * @return
     * @throws IOException
     */
    public String getValidateToken(String appid, String secret) throws IOException {
        String currentToken = getTokenCheckTimeOut(appid, secret);
        if (StringUtils.isBlank(currentToken)) {
            currentToken = getAccessToken(appid, secret);
        }
        return currentToken;
    }

    /**
     * 如果超时返回空
     * @param appid
     * @param secret
     * @return
     */
    private String getTokenCheckTimeOut(String appid, String secret) {
        //设置key
        StringBuffer key = new StringBuffer(appid);
        key.append(secret);
        Object token = tokenMap.get(key.toString());
        if (null == token) {
            return null;
        } else {
            WxCurrentTokenBean wxCurrentTokenBean = (WxCurrentTokenBean) token;
            long now = System.currentTimeMillis();
            if ((now - wxCurrentTokenBean.getLastQueryTime()) >= 7000 * 1000)  //微信token 7200s 超时  即2小时
            {
                return null;
            }
            return wxCurrentTokenBean.getToken();
        }
    }

    /**
     * @param url
     * @return
     * @throws IOException
     * @throws ClientProtocolException
     * @desc 发起HTTP GET请求返回数据
     */
    private String executeHttpGet(String url) throws IOException, ClientProtocolException {
        ResponseHandler<?> responseHandler = new BasicResponseHandler();
        HttpGet httpGet = new HttpGet(url);
        String response = (String) this.webClient.execute(httpGet, responseHandler);
        httpGet.releaseConnection();
        log.info("return response=====start======");
        log.info(response);
        log.info("return response=====end======");
        return response;
    }

    public static void main(String[] args) throws IOException {
        WxMessageBean wxMessageBean = new WxMessageBean();
        wxMessageBean.setAppId("wxb929e4f92eb0b17c");
        wxMessageBean.setAppSecu("af17c8f2790e92d11021b87b173bf7de");
        wxMessageBean.setMessage("你好啊。测试环节");
        wxMessageBean.setOpenId("oJ_wBuOQC0aDjLFNfA0c_x6o3meE");
        WxHelperContext.getWxHelperContext().sendMessageCore(wxMessageBean);
//        WxHelperContext wxHelperContext = new WxHelperContext();
//        wxHelperContext.initWebClient();
//        String token = wxHelperContext.getAccessToken("wxb929e4f92eb0b17c", "af17c8f2790e92d11021b87b173bf7de");
//
//        String hmtl = "Hello World";
//        String msg = "{\"touser\":\"oJ_wBuOQC0aDjLFNfA0c_x6o3meE\",\"msgtype\":\"text\",\"text\":{\"content\":\"" + hmtl + "\"}}";
//        wxHelperContext.sendMessage(token, msg);

    }
}
